********/
-static inline void free_shadow_page( struct mm_struct *m, unsigned int pfn )
+static inline void free_shadow_page( struct mm_struct *m,
+ struct pfn_info *pfn_info )
{
unsigned long flags;
+ unsigned long type = pfn_info->type_and_flags & PGT_type_mask;
m->shadow_page_count--;
+ if (type == PGT_l1_page_table)
+ perfc_decr(shadow_l1_pages);
+ else if (type == PGT_l2_page_table)
+ perfc_decr(shadow_l2_pages);
+ else printk("Free shadow weird page type pfn=%08x type=%08lx\n",
+ frame_table-pfn_info, pfn_info->type_and_flags);
+
+
+ pfn_info->type_and_flags = 0;
+
spin_lock_irqsave(&free_list_lock, flags);
- list_add(&frame_table[pfn].list, &free_list);
+ list_add(&pfn_info->list, &free_list);
free_pfns++;
spin_unlock_irqrestore(&free_list_lock, flags);
}
static void __free_shadow_table( struct mm_struct *m )
{
- int j;
- struct shadow_status *a;
+ int j, free=0;
+ struct shadow_status *a,*next;
// the code assumes you're not using the page tables i.e.
// the domain is stopped and cr3 is something else!!
// walk the hash table and call free_shadow_page on all pages
+ shadow_audit(m,1);
+
for(j=0;j<shadow_ht_buckets;j++)
{
a = &m->shadow_ht[j];
if (a->pfn)
{
- free_shadow_page( m, a->spfn_and_flags & PSH_pfn_mask );
+ free_shadow_page( m,
+ &frame_table[a->spfn_and_flags & PSH_pfn_mask] );
a->pfn = 0;
a->spfn_and_flags = 0;
+ free++;
}
- a=a->next;
+ next=a->next;
+ a->next=NULL;
+ a=next;
while(a)
{
struct shadow_status *next = a->next;
- free_shadow_page( m, a->spfn_and_flags & PSH_pfn_mask );
+
+ free_shadow_page( m,
+ &frame_table[a->spfn_and_flags & PSH_pfn_mask] );
a->pfn = 0;
a->spfn_and_flags = 0;
- a->next = m->shadow_ht_free;
+ free++;
+ a->next = m->shadow_ht_free;
m->shadow_ht_free = a;
a=next;
}
+ shadow_audit(m,0);
}
+ SH_LOG("Free shadow table. Freed= %d",free);
}
+static inline int shadow_page_op( struct mm_struct *m, unsigned int op,
+ struct pfn_info *spfn_info )
+{
+ int work = 0;
+ unsigned int spfn = spfn_info-frame_table;
-int shadow_mode_enable( struct mm_struct *m, unsigned int mode )
+ switch( op )
+ {
+ case DOM0_SHADOW_CONTROL_OP_CLEAN:
+ {
+ int i;
+ if ( (spfn_info->type_and_flags & PGT_type_mask) ==
+ PGT_l1_page_table )
+ {
+ unsigned long * spl1e = map_domain_mem( spfn<<PAGE_SHIFT );
+
+ for (i=0;i<ENTRIES_PER_L1_PAGETABLE;i++)
+ {
+ if ( spl1e[i] & _PAGE_RW )
+ {
+ work++;
+ spl1e[i] &= ~_PAGE_RW;
+ }
+ }
+ unmap_domain_mem( spl1e );
+ }
+ }
+ }
+ return work;
+}
+static void __scan_shadow_table( struct mm_struct *m, unsigned int op )
{
+ int j, work=0;
+ struct shadow_status *a;
+
+ // the code assumes you're not using the page tables i.e.
+ // the domain is stopped and cr3 is something else!!
+
+ // walk the hash table and call free_shadow_page on all pages
+
+ shadow_audit(m,1);
+
+ for(j=0;j<shadow_ht_buckets;j++)
+ {
+ a = &m->shadow_ht[j];
+ if (a->pfn)
+ {
+ work += shadow_page_op( m, op, &frame_table[a->spfn_and_flags & PSH_pfn_mask] );
+ }
+ a=a->next;
+ while(a)
+ {
+ work += shadow_page_op( m, op, &frame_table[a->spfn_and_flags & PSH_pfn_mask] );
+ a=a->next;
+ }
+ shadow_audit(m,0);
+ }
+ SH_LOG("Scan shadow table. Work=%d l1=%d l2=%d", work, perfc_value(shadow_l1_pages), perfc_value(shadow_l2_pages));
+}
+
+
+int shadow_mode_enable( struct task_struct *p, unsigned int mode )
+{
+ struct mm_struct *m = &p->mm;
struct shadow_status **fptr;
int i;
memset( m->shadow_ht_extras, 0, sizeof(void*) + (shadow_ht_extra_size *
sizeof(struct shadow_status)) );
+
+ m->shadow_extras_count++;
// add extras to free list
fptr = &m->shadow_ht_free;
*((struct shadow_status ** )
&m->shadow_ht_extras[shadow_ht_extra_size]) = NULL;
+ if ( mode == SHM_logdirty )
+ {
+ m->shadow_dirty_bitmap = kmalloc( p->max_pages/8, GFP_KERNEL );
+ if( !m->shadow_dirty_bitmap ) goto nomem;
+ memset(m->shadow_dirty_bitmap,0,p->max_pages/8);
+ }
+
spin_unlock(&m->shadow_lock);
// call shadow_mk_pagetable
return -ENOMEM;
}
-static void shadow_mode_disable( struct mm_struct *m )
+static void shadow_mode_disable( struct task_struct *p )
{
+ struct mm_struct *m = &p->mm;
+ struct shadow_status *next;
+
+ spin_lock(&m->shadow_lock);
+ __free_shadow_table( m );
+ m->shadow_mode = 0;
+ spin_unlock(&m->shadow_lock);
+
+ SH_LOG("freed tables count=%d l1=%d l2=%d",
+ m->shadow_page_count, perfc_value(shadow_l1_pages), perfc_value(shadow_l2_pages));
+
+ next = m->shadow_ht_extras;
+ while( next )
+ {
+ struct shadow_status * this = next;
+ m->shadow_extras_count--;
+ next = *((struct shadow_status **)(&next[shadow_ht_extra_size]));
+ kfree( this );
+ }
- // free the hash buckets as you go
+ SH_LOG("freed extras, now %d", m->shadow_extras_count);
+
+ if( m->shadow_dirty_bitmap )
+ {
+ kfree( m->shadow_dirty_bitmap );
+ m->shadow_dirty_bitmap = 0;
+ }
// free the hashtable itself
+ kfree( &m->shadow_ht[0] );
}
-static void shadow_mode_flush( struct mm_struct *m )
+static void shadow_mode_table_op( struct task_struct *p, unsigned int op )
{
+ struct mm_struct *m = &p->mm;
// since Dom0 did the hypercall, we should be running with it's page
// tables right now. Calling flush on yourself would be really
return;
}
+
spin_lock(&m->shadow_lock);
- __free_shadow_table( m );
+
+ SH_LOG("shadow mode table op %08lx %08lx count %d",pagetable_val( m->pagetable),pagetable_val(m->shadow_table), m->shadow_page_count);
+
+ shadow_audit(m,1);
+
+ switch(op)
+ {
+ case DOM0_SHADOW_CONTROL_OP_FLUSH:
+ __free_shadow_table( m );
+ break;
+
+ case DOM0_SHADOW_CONTROL_OP_CLEAN:
+ __scan_shadow_table( m, op );
+ if( m->shadow_dirty_bitmap )
+ memset(m->shadow_dirty_bitmap,0,p->max_pages/8);
+ break;
+ }
+
spin_unlock(&m->shadow_lock);
+ SH_LOG("shadow mode table op : page count %d", m->shadow_page_count);
+
+ shadow_audit(m,1);
+
// call shadow_mk_pagetable
shadow_mk_pagetable( m );
// don't call if already shadowed...
// sychronously stop domain
- if( !(p->state & TASK_STOPPED) && !(p->state & TASK_PAUSED))
+ if( 0 && !(p->state & TASK_STOPPED) && !(p->state & TASK_PAUSED))
{
+ printk("about to pause domain\n");
sched_pause_sync(p);
printk("paused domain\n");
we_paused = 1;
}
- if (p->mm.shadow_mode && op == DOM0_SHADOW_CONTROL_OP_OFF )
+ if ( p->mm.shadow_mode && op == DOM0_SHADOW_CONTROL_OP_OFF )
{
- shadow_mode_disable(&p->mm);
+ shadow_mode_disable(p);
}
- else if (p->mm.shadow_mode && op == DOM0_SHADOW_CONTROL_OP_ENABLE_TEST )
+ else if ( op == DOM0_SHADOW_CONTROL_OP_ENABLE_TEST )
{
- shadow_mode_disable(&p->mm);
- shadow_mode_enable(&p->mm, SHM_test);
+ if(p->mm.shadow_mode) shadow_mode_disable(p);
+ shadow_mode_enable(p, SHM_test);
}
- else if (p->mm.shadow_mode && op == DOM0_SHADOW_CONTROL_OP_FLUSH )
+ else if ( p->mm.shadow_mode && op >= DOM0_SHADOW_CONTROL_OP_FLUSH && op<=DOM0_SHADOW_CONTROL_OP_CLEAN )
{
- shadow_mode_flush(&p->mm);
+ shadow_mode_table_op(p, op);
}
else
{
+ if ( we_paused ) wake_up(p);
return -EINVAL;
}
// this CPU was the one that cmpxchg'ed the page to invalid
spfn = __shadow_status(¤t->mm, gpfn) & PSH_pfn_mask;
+
delete_shadow_status(¤t->mm, gpfn);
#if 0 // XXX leave as might be useful for later debugging
}
#endif
- if (type == PGT_l1_page_table)
- perfc_decr(shadow_l1_pages);
- else
- perfc_decr(shadow_l2_pages);
-
- free_shadow_page( ¤t->mm, spfn );
+ free_shadow_page( ¤t->mm, &frame_table[spfn] );
}
SH_VVLOG("shadow_l2_table( %08lx )",gpfn);
perfc_incrc(shadow_l2_table_count);
- perfc_incr(shadow_l2_pages);
// XXX in future, worry about racing in SMP guests
// -- use cmpxchg with PSH_pending flag to show progress (and spin)
ASSERT( spfn_info ); // XXX deal with failure later e.g. blow cache
+ spfn_info->type_and_flags = PGT_l2_page_table;
+ perfc_incr(shadow_l2_pages);
+
spfn = (unsigned long) (spfn_info - frame_table);
// mark pfn as being shadowed, update field to point at shadow
struct pfn_info *sl1pfn_info;
unsigned long *gpl1e, *spl1e;
int i;
- sl1pfn_info = alloc_domain_page( NULL ); // XXX account properly!
+ sl1pfn_info = alloc_shadow_page( ¤t->mm );
+ sl1pfn_info->type_and_flags = PGT_l1_page_table;
+
sl1pfn = sl1pfn_info - frame_table;
SH_VVLOG("4a: l1 not shadowed ( %08lx )",sl1pfn);
#define PSH_pfn_mask ((1<<21)-1)
/* Shadow PT operation mode : shadowmode variable in mm_struct */
-#define SHM_test (1<<0) /* just run domain on shadow PTs */
-#define SHM_logdirty (1<<1) /* log pages that are dirtied */
-#define SHM_cow (1<<2) /* copy on write all dirtied pages */
-#define SHM_translate (1<<3) /* lookup machine pages in translation table */
+#define SHM_test (1) /* just run domain on shadow PTs */
+#define SHM_logdirty (2) /* log pages that are dirtied */
+#define SHM_cow (3) /* copy on write all dirtied pages */
+#define SHM_translate (4) /* lookup machine pages in translation table */
#define shadow_linear_pg_table ((l1_pgentry_t *)SH_LINEAR_PT_VIRT_START)
#define shadow_linear_l2_table ((l2_pgentry_t *)(SH_LINEAR_PT_VIRT_START+(SH_LINEAR_PT_VIRT_START>>(L2_PAGETABLE_SHIFT-L1_PAGETABLE_SHIFT))))
l1_pgentry_t **prev_spl1e_ptr );
extern void shadow_l2_normal_pt_update( unsigned long pa, unsigned long gpte );
extern void unshadow_table( unsigned long gpfn, unsigned int type );
-extern int shadow_mode_enable( struct mm_struct *m, unsigned int mode );
+extern int shadow_mode_enable( struct task_struct *p, unsigned int mode );
extern unsigned long shadow_l2_table(
struct mm_struct *m, unsigned long gpfn );
for(j=0;j<shadow_ht_buckets;j++)
{
- a = &p->mm.shadow_ht[j];
- if(a->pfn) live++;
- while(a->next && live<9999)
+ a = &m->shadow_ht[j];
+ if(a->pfn){live++; ASSERT(a->spfn_and_flags&PSH_pfn_mask);}
+ ASSERT((a->pfn&0xf0000000)==0);
+ ASSERT(a->pfn<0x00100000);
+ a=a->next;
+ while(a && live<9999)
{
live++;
- if(a->pfn == 0)
+ if(a->pfn == 0 || a->spfn_and_flags == 0)
{
printk("XXX live=%d pfn=%08lx sp=%08lx next=%p\n",
live, a->pfn, a->spfn_and_flags, a->next);
BUG();
}
+ ASSERT(a->pfn);
+ ASSERT((a->pfn&0xf0000000)==0);
+ ASSERT(a->pfn<0x00100000);
+ ASSERT(a->spfn_and_flags&PSH_pfn_mask);
a=a->next;
}
ASSERT(live<9999);
}
- a = p->mm.shadow_ht_free;
+ a = m->shadow_ht_free;
while(a) { free++; a=a->next; }
- if(print) printk("live=%d free=%d\n",live,free);
+ if(print) printk("Xlive=%d free=%d\n",live,free);
abs=(perfc_value(shadow_l1_pages)+perfc_value(shadow_l2_pages))-live;
if( abs < -1 || abs > 1 )
b->next = b->next->next;
D->next = m->shadow_ht_free;
+ D->pfn = 0;
+ D->spfn_and_flags = 0;
m->shadow_ht_free = D;
}
else
#if SHADOW_HASH_DEBUG
if( __shadow_status(m,gpfn) ) BUG();
+ shadow_audit(m,0);
#endif
return;
}
#if SHADOW_HASH_DEBUG
if( __shadow_status(m,gpfn) ) BUG();
#endif
+ shadow_audit(m,0);
return;
}
B = b = hash_bucket( m, gpfn );
ASSERT(gpfn);
- ASSERT(s);
+ //ASSERT(s);
+ //ASSERT(s&PSH_pfn_mask);
SH_VVLOG("set gpfn=%08x s=%08lx bucket=%p(%p)", gpfn, s, b, b->next );
+
shadow_audit(m,0);
do
if ( b->pfn == gpfn )
{
b->spfn_and_flags = s;
+ shadow_audit(m,0);
return;
}
ASSERT( B->next == 0 );
B->pfn = gpfn;
B->spfn_and_flags = s;
+ shadow_audit(m,0);
return;
}
memset( extra, 0, sizeof(void*) + (shadow_ht_extra_size *
sizeof(struct shadow_status)) );
+
+ m->shadow_extras_count++;
// add extras to free list
fptr = &m->shadow_ht_free;
}
*fptr = NULL;
- *((struct shadow_status ** ) &m->shadow_ht[shadow_ht_extra_size]) =
+ *((struct shadow_status ** ) &extra[shadow_ht_extra_size]) =
m->shadow_ht_extras;
m->shadow_ht_extras = extra;
b->next = B->next;
B->next = b;
+ shadow_audit(m,0);
+
return;
}